<?php

/**
 * MyQEE 文件核心类
 *
 * @author	 jonwang(jonwang@myqee.com)
 * @category   MyQEE
 * @package	System
 * @subpackage Core
 * @copyright  Copyright (c) 2008-2011 myqee.com
 * @license	http://www.myqee.com/license.html
 */
class MyQEE_File
{

    /**
     * 创建一个文件
     * @param string $file
     * @param $data
     * @return boolean
     */
    public static function create_file($file, $data)
    {
        if ( @file_put_contents($file, $data) )
        {
            return true;
        }
        else
        {
            return false;
        }
    }

    /**
     * 循环建立目录
     *
     * @param string $dir 待创建的文件夹
     * @param boolean $createdefaulfile 对于新创建的文件夹，是否自动创建空默认页
     * @return boolean true/false
     */
    public static function create_dir($dir, $createdefaulfile = true)
    {
        if ( ! is_dir($dir) )
        {
            $temp = explode('/', str_replace('\\', '/', $dir) );
            $cur_dir = "";
            for( $i = 0; $i < count($temp); $i ++ )
            {
                $cur_dir .= $temp[$i] . "/";
                if ( ! is_dir($cur_dir) )
                {
                    if ( mkdir($cur_dir, 0755) )
                    {
                        if ( $createdefaulfile ) File::create_file($cur_dir . 'index.html', ' ');
                    }
                    else
                    {
                        return false;
                    }
                }
            }
        }
        return true;
    }

    /**
     * 循环删除目录下的所有目录和文件
     *
     * @param string $dirName
     * @return boolean
     */
    public static function remove_dir($dirName)
    {
        if ( ! is_dir($dirName) )
        {
            return true;
        }

        $realpath = realpath($dirName);
        static $safe_dir = array(
            DIR_BULIDER,
            DIR_DATA,
            DIR_LIBRARY,
            DIR_PROJECT,
            DIR_SHELL,
            DIR_SYSTEM,
            DIR_TEMP,
            DIR_WWWROOT,
        );
        if ( ! $realpath || in_array($realpath.DIRECTORY_SEPARATOR, $safe_dir) )
        {
            return false;
        }

        $handle = opendir($dirName);
        while ( ($file = readdir($handle)) !== false )
        {
            if ( $file != '.' && $file != '..' )
            {
                $dir = $dirName . DIRECTORY_SEPARATOR . $file;
                is_dir($dir) ? File::remove_dir($dir) : @unlink($dir);
            }
        }
        closedir($handle);
        return @rmdir($dirName);
    }

    /**
     * 转移目录下的所有目录和文件
     *
     * @param string $fromdir  源文文件目录
     * @param string $todir  目标文件目录
     * @param boolean $autocoverageold 是否覆盖已有文件，true覆盖，false跳过
     * @return array($dook,$doerror)
     */
    public static function move_dir($fromdir, $todir, $autocoverageold = true)
    {
        $fromdir = rtrim($fromdir, '/') . '/';
        $todir = rtrim($todir, '/') . '/';
        if ( ! is_dir($fromdir) || $fromdir == $todir ) return false;
        $files = glob($fromdir . '*');
        $donum = array(0, 0);
        foreach ( $files as $path )
        {
            $tofile = $todir . basename($path);
            if ( is_dir($path) )
            {
                File::create_dir($tofile);
                $donum2 = File::move_dir($path, $tofile, $autocoverageold);
                if ( $donum2 )
                {
                    $donum[0] += $donum2[0];
                    $donum[1] += $donum2[1];
                }
            }
            else
            {
                if ( $autocoverageold && file_exists($tofile) )
                {
                    //覆盖已有文件
                    unlink($tofile);
                }
                if ( rename($path, $tofile) )
                {
                    $donum[0] ++;
                }
                else
                {
                    $donum[1] ++;
                }
            }
        }
        //移除旧目录
        File::remove_dir($fromdir);
        return $donum;
    }


	/**
	 * 返回指定文件类型
	 *
	 *     $mime = File::mime($file);
	 *
	 * @param   string  file name or path
	 * @return  string  mime type on success
	 * @return  FALSE   on failure
	 */
	public static function mime($filename)
	{
		// Get the complete path to the file
		$filename = realpath($filename);

		// Get the extension from the filename
		$extension = strtolower(pathinfo($filename, PATHINFO_EXTENSION));

		if (preg_match('/^(?:jpe?g|png|[gt]if|bmp|swf)$/', $extension))
		{
			// Use getimagesize() to find the mime type on images
			$file = getimagesize($filename);

			if (isset($file['mime']))
				return $file['mime'];
		}

		if (class_exists('finfo', FALSE))
		{
			if ($info = new finfo(defined('FILEINFO_MIME_TYPE') ? FILEINFO_MIME_TYPE : FILEINFO_MIME))
			{
				return $info->file($filename);
			}
		}

		if (ini_get('mime_magic.magicfile') AND function_exists('mime_content_type'))
		{
			// The mime_content_type function is only useful with a magic file
			return mime_content_type($filename);
		}

		if ( ! empty($extension))
		{
			return File::mime_by_ext($extension);
		}

		// Unable to find the mime-type
		return FALSE;
	}

	/**
	 * Return the mime type of an extension.
	 *
	 *     $mime = File::mime_by_ext('png'); // "image/png"
	 *
	 * @param   string  extension: php, pdf, txt, etc
	 * @return  string  mime type on success
	 * @return  FALSE   on failure
	 */
	public static function mime_by_ext($extension)
	{
		// Load all of the mime types
		$mimes = Core::config('mimes');

		return isset($mimes[$extension]) ? $mimes[$extension][0] : FALSE;
	}

	/**
	 * Lookup MIME types for a file
	 *
	 * @see Kohana_File::mime_by_ext()
	 * @param string $extension Extension to lookup
	 * @return array Array of MIMEs associated with the specified extension
	 */
	public static function mimes_by_ext($extension)
	{
		// Load all of the mime types
		$mimes = Core::config('mimes');

		return isset($mimes[$extension]) ? ( (array) $mimes[$extension]) : array();
	}

	/**
	 * Lookup file extensions by MIME type
	 *
	 * @param   string  $type File MIME type
	 * @return  array   File extensions matching MIME type
	 */
	public static function exts_by_mime($type)
	{
		static $types = array();

		// Fill the static array
		if (empty($types))
		{
			foreach (Core::config('mimes') as $ext => $mimes)
			{
				foreach ($mimes as $mime)
				{
					if ($mime == 'application/octet-stream')
					{
						// octet-stream is a generic binary
						continue;
					}

					if ( ! isset($types[$mime]))
					{
						$types[$mime] = array( (string) $ext);
					}
					elseif ( ! in_array($ext, $types[$mime]))
					{
						$types[$mime][] = (string) $ext;
					}
				}
			}
		}

		return isset($types[$type]) ? $types[$type] : FALSE;
	}

	/**
	 * Lookup a single file extension by MIME type.
	 *
	 * @param   string  $type  MIME type to lookup
	 * @return  mixed          First file extension matching or false
	 */
	public static function ext_by_mime($type)
	{
		return current(File::exts_by_mime($type));
	}

	/**
	 * Split a file into pieces matching a specific size. Used when you need to
	 * split large files into smaller pieces for easy transmission.
	 *
	 *     $count = File::split($file);
	 *
	 * @param   string   file to be split
	 * @param   string   directory to output to, defaults to the same directory as the file
	 * @param   integer  size, in MB, for each piece to be
	 * @return  integer  The number of pieces that were created
	 */
	public static function split($filename, $piece_size = 10)
	{
		// Open the input file
		$file = fopen($filename, 'rb');

		// Change the piece size to bytes
		$piece_size = floor($piece_size * 1024 * 1024);

		// Write files in 8k blocks
		$block_size = 1024 * 8;

		// Total number of peices
		$peices = 0;

		while ( ! feof($file))
		{
			// Create another piece
			$peices += 1;

			// Create a new file piece
			$piece = str_pad($peices, 3, '0', STR_PAD_LEFT);
			$piece = fopen($filename.'.'.$piece, 'wb+');

			// Number of bytes read
			$read = 0;

			do
			{
				// Transfer the data in blocks
				fwrite($piece, fread($file, $block_size));

				// Another block has been read
				$read += $block_size;
			}
			while ($read < $piece_size);

			// Close the piece
			fclose($piece);
		}

		// Close the file
		fclose($file);

		return $peices;
	}

	/**
	 * Join a split file into a whole file. Does the reverse of [File::split].
	 *
	 *     $count = File::join($file);
	 *
	 * @param   string   split filename, without .000 extension
	 * @param   string   output filename, if different then an the filename
	 * @return  integer  The number of pieces that were joined.
	 */
	public static function join($filename)
	{
		// Open the file
		$file = fopen($filename, 'wb+');

		// Read files in 8k blocks
		$block_size = 1024 * 8;

		// Total number of peices
		$pieces = 0;

		while (is_file($piece = $filename.'.'.str_pad($pieces + 1, 3, '0', STR_PAD_LEFT)))
		{
			// Read another piece
			$pieces += 1;

			// Open the piece for reading
			$piece = fopen($piece, 'rb');

			while ( ! feof($piece))
			{
				// Transfer the data in blocks
				fwrite($file, fread($piece, $block_size));
			}

			// Close the peice
			fclose($piece);
		}

		return $pieces;
	}
}